package com.openwater.effect;

import java.nio.FloatBuffer;
import java.util.Random;

import android.opengl.GLES20;
import android.os.SystemClock;

import com.openwater.tools.BufferAllocator;
import com.openwater.tools.math.MatrixState;

public class ParticleSystem {

    private float mTime = 0.0f;

    private int mProgram;
    private int mCenterPosHandle;
    private int mStartPosHandle;
    private int mEndPosHandle;
    private int mColorHandle;
    private int mTimeHandle;
    private int mLifeTimeHandle;
    private int mSamplerHandle;
    private int muMVPMatrixHandle;

    private final int NUM_PARTICLES = 1000;
    private final int PARTICLE_SIZE = 7;
    private final float[] mParticleData = new float[NUM_PARTICLES * PARTICLE_SIZE]; 
    private FloatBuffer mParticles;
    
    public ParticleSystem(int program) {
        initShader(program);
        initVertex();
    }

    private void initVertex(){
        // Fill in particle data array
        Random generator = new Random();
        for ( int i = 0; i < NUM_PARTICLES; i++ ){
           // Lifetime of particle
           mParticleData[i * 7 + 0] = generator.nextFloat();

           // End position of particle ,[-1,1)
           mParticleData[i * 7 + 1] = generator.nextFloat() * 2.0f - 1.0f;
           mParticleData[i * 7 + 2] = generator.nextFloat() * 2.0f - 1.0f;
           mParticleData[i * 7 + 3] = generator.nextFloat() * 2.0f - 1.0f;

           // Start position of particle ,[-0.125,0.125)
           mParticleData[i * 7 + 4] = generator.nextFloat() * 0.25f - 0.125f;
           mParticleData[i * 7 + 5] = generator.nextFloat() * 0.25f - 0.125f;
           mParticleData[i * 7 + 6] = generator.nextFloat() * 0.25f - 0.125f;
        }
        mParticles = BufferAllocator.toFloatBuffer(mParticleData);
        // Initialize time to cause reset on first update
        mTime = 1.0f;
    }

    private void initShader(int program) {
        mProgram = program;
        mCenterPosHandle = GLES20.glGetUniformLocation(mProgram,"uCenterPosition");
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "uColor");
        mTimeHandle = GLES20.glGetUniformLocation(mProgram, "uTime");
        mStartPosHandle = GLES20.glGetAttribLocation(mProgram,"aStartPosition");
        mEndPosHandle = GLES20.glGetAttribLocation(mProgram,"aEndPosition");
        mLifeTimeHandle = GLES20.glGetAttribLocation(mProgram,"aLifeTime");
        mSamplerHandle = GLES20.glGetUniformLocation (mProgram, "sTexture" );
        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    }

    private long mLastTime = 0;

    public void update() {

        if(mLastTime == 0){
            mLastTime = SystemClock.uptimeMillis();
        }
        long curTime  = SystemClock.uptimeMillis();
        long elapsedTime = curTime - mLastTime;
        float deltaTime = elapsedTime / 1000.0f;
        mLastTime = curTime;
        
        mTime += deltaTime;
        
        if (mTime >= 1.0f) {
            mTime = 0.0f;

            //Pick a new start location and color
            float x = (float) (Math.random() - 0.5f);
            float y = (float) (Math.random() - 0.5f);
            float z = (float) (Math.random() - 0.5f);
            GLES20.glUniform3f(mCenterPosHandle, x, y, z);

            //Random color
            float r = (float) (Math.random() * 0.5f + 0.5f);
            float g = (float) (Math.random() * 0.5f + 0.5f);
            float b = (float) (Math.random() * 0.5f + 0.5f);
            float a = 0.5f;
            GLES20.glUniform4f(mColorHandle, r,g,b,a);
        }
        GLES20.glUniform1f(mTimeHandle, mTime);
    }

    public void drawSelf(int texid){
        update();
        GLES20.glUseProgram(mProgram);
        // Load the vertex attributes
        mParticles.position(0);
        GLES20.glVertexAttribPointer ( mLifeTimeHandle, 1, GLES20.GL_FLOAT, 
                                       false, PARTICLE_SIZE * 4, 
                                       mParticles );
        mParticles.position(1);
        GLES20.glVertexAttribPointer ( mEndPosHandle, 3, GLES20.GL_FLOAT,
                                       false, PARTICLE_SIZE * 4,
                                       mParticles );

        mParticles.position(4);
        GLES20.glVertexAttribPointer ( mStartPosHandle, 3, GLES20.GL_FLOAT,
                                       false, PARTICLE_SIZE * 4,
                                       mParticles );
        GLES20.glEnableVertexAttribArray (mLifeTimeHandle);
        GLES20.glEnableVertexAttribArray (mEndPosHandle);
        GLES20.glEnableVertexAttribArray (mStartPosHandle);

        // Blend particles
        GLES20.glEnable ( GLES20.GL_BLEND );
        GLES20.glBlendFunc ( GLES20.GL_SRC_ALPHA, GLES20.GL_ONE );

        // Bind the texture
        GLES20.glActiveTexture ( GLES20.GL_TEXTURE0 );
        GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, texid );
        GLES20.glEnable ( GLES20.GL_TEXTURE_2D );

        // Set the sampler texture unit to 0
        GLES20.glUniform1i (mSamplerHandle,0);
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);

        GLES20.glDrawArrays( GLES20.GL_POINTS, 0, NUM_PARTICLES );
    }


}
